package com.zlp.utils;

import org.springframework.dao.DataAccessException;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.util.UUID;

@Component("redisLock")
public class RedisLock {

	@Resource
	private StringRedisTemplate stringRedisTemplate;



	/**
	 * 获取锁
	 * @param key
	 * @param acquireTimeout 获取锁之前的超时时间（秒）
	 * @param timeOut  过期时间（秒）
	 * @return
	 */

	public String getLock(String key,long acquireTimeout, long timeOut) {
		String uuid = UUID.randomUUID().toString();
		// 预估该方法执行时间
		Long endTime = System.currentTimeMillis() + (acquireTimeout * 1000);
		String result = stringRedisTemplate.execute(new RedisCallback<String>() {
			@Override
			public String doInRedis(RedisConnection redisConnection) throws DataAccessException {
				// 定义在没有获取锁之前,锁的超时时间
				while (System.currentTimeMillis() < endTime) {
					RedisSerializer<String> redisSerializer = stringRedisTemplate.getStringSerializer();
					byte[] keySerialize = redisSerializer.serialize(key);
					byte[] value = redisSerializer.serialize(uuid);
					// 使用setnx方法设置锁值
					if(redisConnection.setNX(keySerialize, value)) {
						redisConnection.expire(keySerialize, timeOut);
						return uuid;
					}
				}
				return null;
			}
		});
		return result;
	}

	/**
	 * 释放锁
	 * @param key
	 * @param value
	 */
	public Boolean unLock(String key,String value) {
		// 如果该锁的id 等于value 是同一把锁情况才可以删除
		if (getString(key) != null) {
			if (getString(key).equals(value)) {
				return delete(key);
			}
		}
		return false;
	}

	/**
	 * 根据对应的key删除key
	 *
	 * @param key
	 */
	public Boolean delete(String key) {
		return stringRedisTemplate.delete(key);
	}

	/**
	 * 根据key查询string类型
	 *
	 * @param key
	 * @return
	 */
	public String getString(String key) {
		String value = stringRedisTemplate.opsForValue().get(key);
		return value;
	}


}
